﻿using System;
using System.Linq;
using System.Net;


namespace FirmaKurierska.Models
{
    /// <summary>
    /// Klasa operująca na odległościach i czasach przesyłek
    /// </summary>
    public class Lokalizacja
    {

        public string MiejsceNadania { get; set; }
        public string UlicaNadania { get; set; }
        public string NumerDomuNadania { get; set; }
        public string MiejsceDostarczenia { get; set; }
        public string UlicaDostarczenia { get; set; }
        public string NumerDomuDostarczenia { get; set; }
        public DateTime CzasNadania { get; set; }
        public DateTime CzasDostarczenia { get { return wyliczCzasDostarczenia(); } set { } }
        public string Miejsce { get { return przeliczLokalizacjePrzesylek(); } set { } }
        public bool Istnieje { get { return wyliczOdleglosc(); } set { } }
        public double czasGoogle;
        public double odlegloscGoogle;
        public string Lat;
        public string Lng;


        /// <summary>
        /// Wylicza dokładną lokalizację przesyłki
        /// </summary>
        /// <returns>Opis reprezentujący lokalizację przesyłki</returns>
        private String przeliczLokalizacjePrzesylek()
        {
            wyliczOdleglosc();
            // wyliczCzasDostarczenia();
            double predkosc = odlegloscGoogle / czasGoogle;
            DateTime aktualnyCzas = DateTime.Now;
            DateTime czasWyruszenia = new DateTime(CzasDostarczenia.Year, CzasDostarczenia.Month, CzasDostarczenia.Day, 8, 0, 0);
            int czasJakUplynalSek = (Int32)(aktualnyCzas.Subtract(czasWyruszenia)).TotalSeconds;
            int przemierzonyDystans = (int)predkosc * czasJakUplynalSek;
            if (czasJakUplynalSek < 0)
            {
                przemierzonyDystans = 0;
                czasJakUplynalSek = 0;
            }

            if (aktualnyCzas.Day < czasWyruszenia.Day)
            {
                return " miejscowosci nadawcy (pobranie do bazy)";
            }

            if (przemierzonyDystans >= odlegloscGoogle)
                return " miejscowosci odbiorcy";

            var m_strfilepath =
                "http://maps.googleapis.com/maps/api/directions/xml?origin="
                + MiejsceNadania + "+" + UlicaNadania + "+" + NumerDomuNadania
                + "&destination=" + MiejsceDostarczenia + "+" + UlicaDostarczenia + "+" + NumerDomuDostarczenia
                + "&sensor=false&units=metric";

            string xmlStr;
            using (var wc = new WebClient())
            {
                xmlStr = wc.DownloadString(m_strfilepath);
            }
            double suma = 0;
            int i = 0;
            string[] xmlT = xmlStr.Split(' ');
            string lat = "", lng = "";
            foreach (string s in xmlT)
            {
                if (System.Text.RegularExpressions.Regex.IsMatch(s, "<end_location>", System.Text.RegularExpressions.RegexOptions.IgnoreCase))
                {
                    lat = xmlT[i + 5];
                    lng = xmlT[i + 10];
                    string[] lt = (xmlT[i + 5]).Split(new string[] { ">", "<" }, StringSplitOptions.None);
                    {
                        lat = lt[2];
                    }
                    string[] lg = (xmlT[i + 10]).Split(new string[] { ">", "<" }, StringSplitOptions.None);
                    {
                        lng = lg[2];
                    }
                }
                if (System.Text.RegularExpressions.Regex.IsMatch(s, "<distance>", System.Text.RegularExpressions.RegexOptions.IgnoreCase))
                {
                    if (xmlT[i + 5] != "")
                    {
                        string[] t = (xmlT[i + 5]).Split(new string[] { ">", "<" }, StringSplitOptions.None);
                        if (t != null)
                        {
                            suma += Convert.ToDouble(t[2]);
                            if (i < 20)
                                return " miejscowosci nadawcy";
                            if (suma > przemierzonyDystans)
                            {
                                Lat = lat;
                                Lng = lng;
                                var cityName = "https://maps.googleapis.com/maps/api/geocode/json?latlng=" +
                                    lat + "," + lng + "&result_type=administrative_area_level_3&key=AIzaSyCzwe_Zb0pFjezEdJ3rj6D_q9jW_1sXhrM";
                                string xmlCityStr;
                                using (var wc = new WebClient())
                                {
                                    xmlCityStr = wc.DownloadString(cityName);
                                }
                                string tmp = (xmlCityStr.Substring(xmlCityStr.IndexOf("formatted_address") + 22)).Substring(0, (xmlCityStr.Substring(xmlCityStr.IndexOf("formatted_address") + 22)).IndexOf("\""));
                                return tmp;
                            }
                        }
                    }

                }
                i++;
            }
            return "";
        }

        /// <summary>
        /// Sprawdza czy mozliwe jest wyznaczenie trasy
        /// </summary>
        /// <returns>true jesli trasa istnieje</returns>
        private bool wyliczOdleglosc()
        {
            var m_strFilePath =
                "http://maps.googleapis.com/maps/api/distancematrix/xml?origins="
                + MiejsceNadania + "+" + UlicaNadania + "+" + NumerDomuNadania
                + "&destinations=" + MiejsceDostarczenia + "+" + UlicaDostarczenia + "+" + NumerDomuDostarczenia
                + "&mode=driving&language=pl-PL&sensor=false";
            string xmlStr;
            using (var wc = new WebClient())
            {
                xmlStr = wc.DownloadString(m_strFilePath);
            }
            //sprawdzenie czy trasa istnieje
            bool tmpb;
            string tmp = (xmlStr.Substring(xmlStr.IndexOf("<element>") + 21)).Substring(0, (xmlStr.Substring(xmlStr.IndexOf("<element>") + 21)).IndexOf("</s"));
            if (tmp.Equals("NOT_FOUND"))
            {
                tmpb = false;
                return tmpb;
            }
            else tmpb = true;

            //zczytanie czasu podanego przez google
            czasGoogle = Convert.ToDouble((xmlStr.Substring(xmlStr.IndexOf("<duration>") + 22)).Substring(0, (xmlStr.Substring(xmlStr.IndexOf("<duration>") + 22)).IndexOf("</v")));

            //odleglosci google
            odlegloscGoogle = Convert.ToDouble((xmlStr.Substring(xmlStr.IndexOf("<distance>") + 22)).Substring(0, (xmlStr.Substring(xmlStr.IndexOf("<distance>") + 22)).IndexOf("</v")));
            return tmpb;
        }

        /// <summary>
        /// Wylicza odległość pomiędzy dwoma miejscami
        /// </summary>
        /// <param name="ulica">Ulica pierwszego miejsca</param>
        /// <param name="nrDomu">Nr domu pierwszego miejsca</param>
        /// <param name="miejscowosc">Miejscowość pierwszego miejsca</param>
        /// <param name="ulica2">Ulica drugiego miejsca</param>
        /// <param name="nrDomu2">Nr domu drugiego miejsca</param>
        /// <param name="miejscowosc2">Miejscowość drugiego miejsca</param>
        /// <returns>Odległość (metry)</returns> 
        public int wyliczOdleglosc(string ulica, int nrDomu, string miejscowosc, string ulica2, int nrDomu2, string miejscowosc2)
        {
            MiejsceNadania = miejscowosc;
            UlicaNadania = ulica;
            NumerDomuNadania = Convert.ToString(nrDomu);
            MiejsceDostarczenia = miejscowosc2;
            UlicaDostarczenia = ulica2;
            NumerDomuDostarczenia = Convert.ToString(nrDomu2);
            var m_strFilePath =
                "http://maps.googleapis.com/maps/api/distancematrix/xml?origins="
                + MiejsceNadania + "+" + UlicaNadania + "+" + NumerDomuNadania
                + "&destinations=" + MiejsceDostarczenia + "+" + UlicaDostarczenia + "+" + NumerDomuDostarczenia
                + "&mode=driving&language=pl-PL&sensor=false";
            string xmlStr;
            using (var wc = new WebClient())
            {
                xmlStr = wc.DownloadString(m_strFilePath);
            }
            if (wyliczOdleglosc() == false) return 1000000;
            return Convert.ToInt32(xmlStr.Substring(xmlStr.IndexOf("<distance>") + 22).Substring(0, xmlStr.Substring(xmlStr.IndexOf("<distance>") + 22).IndexOf("</v")));
        }

        /// <summary>
        /// Zwraca id centrali do której powinien być przypisany użytkownik (najbliższa centrala)
        /// </summary>
        /// <param name="ulica">Ulica</param>
        /// <param name="nrDomu">Numer domu</param>
        /// <param name="miejscowosc">Miejscowość</param>
        /// <returns>Id centrali</returns>
        public int konwertujAdresNaIdCentrali(string ulica, int nrDomu, string miejscowosc)
        {
            PlacowkaEntities db = new PlacowkaEntities();
            //Lista centrali
            var centrale = db.Centrale.ToList();
            int id = 0;
            int odleglosc = 10000000;
            foreach (var c in centrale)
            {
                int tmp = wyliczOdleglosc(ulica, nrDomu, miejscowosc, c.ulica, Convert.ToInt32(c.nrDomu), c.Miejscowosc);
                if (tmp < odleglosc)
                {
                    odleglosc = tmp;
                    id = c.Id;
                }
            }
            return id;
        }

        /// <summary>
        /// Wylicza czas dostarczenia aktualnej przesyłki
        /// </summary>
        /// <returns>Czas dostarczenia</returns>
        private DateTime wyliczCzasDostarczenia()
        {
            if (wyliczOdleglosc() == false) return new DateTime();
            DateTime nadanie = CzasNadania;
            double czas = czasGoogle / 3600;
            int dataH = (int)czas;
            int dataM = (int)((czas - dataH) * 60);
            int dataS = (int)((czas - dataH - dataM * 1 / 360) * 100);
            DateTime odbior = new DateTime(nadanie.Year, nadanie.Month, nadanie.Day + 1, dataH + 8, dataM, dataS);
            return odbior;
        }

        /// <summary>
        /// Lokalizuję przesyłkę
        /// </summary>
        /// <param name="id">Id przesyłki</param>
        /// <returns>Informacje o przesyłce</returns>
        public static Lokalizacja lokalizujPrzesylke(long id)
        {
            PlacowkaEntities db = new PlacowkaEntities();
            UsersContext usery = new UsersContext();
            Lokalizacja lokalizacja = new Lokalizacja();

            //var przeszlka1 = (from n in db.Paczka where n.pid == id select n).Single();
            var przesylka = db.Paczka.Find(id);

            ///albo tutaj
            lokalizacja.MiejsceNadania = usery.UserProfiles.Find(przesylka.nadawca_id).Miejscowosc;
            lokalizacja.UlicaNadania = usery.UserProfiles.Find(przesylka.nadawca_id).Ulica;
            lokalizacja.NumerDomuNadania = Convert.ToString(usery.UserProfiles.Find(przesylka.nadawca_id).NrDomu);
            lokalizacja.MiejsceDostarczenia = db.Adresat.Find(przesylka.adresat_id).miasto;
            lokalizacja.UlicaDostarczenia = db.Adresat.Find(przesylka.adresat_id).ulica;
            lokalizacja.NumerDomuDostarczenia = Convert.ToString(db.Adresat.Find(przesylka.adresat_id).nr_domu);
            lokalizacja.CzasNadania = przesylka.data_nadania;

            return lokalizacja;
        }
    }
}